package bee2d.display;

/**
 * ...
 * @author wangjian QQ:421924396
 */
import bee2d.core.Rander;
import bee2d.spritesheet.Frame;
import bee2d.spritesheet.Spritesheet;
import bee2d.spritesheet.Behavior;
import nme.display.DisplayObject;
import nme.display.DisplayObjectContainer;
import nme.display.PixelSnapping;
import nme.display.BitmapData;
import nme.display.Sprite;
import nme.events.Event;
import nme.geom.Point;
import nme.Lib;
import nme.display.Bitmap;
class Animation
{
	public var onUpdate:Void->Void;
	private static var globalId:Int = 0; 
	
	private var _rander:Rander;
	private var frameinx:Int;
	private var _curframe:Frame;
	private var _spritesheet:Spritesheet;
	
	private var behaviorComplete:Bool;
	private var behaviorQueue:Array <String>;
	private var behavior:Behavior;
	private var loopTime:Int;
	private var timeElapsed:Int;
	private var previousTime:Int;
	
	private var _name:String;
	private var _x:Float;
	private var _y:Float;
	private var _alpha:Float;
	private var _scaleX:Float;
	private var _scaleY:Float;
	private var _visible:Bool;
	private var _rotation:Float;
	private var _angle:Float;
	private var _color:Int;
	private var _red:Int;
	private var _green:Int;
	private var _blue:Int;
	
	
	private var _bitmap:Bitmap;
	private var _sprite:Sprite;
	
	public var rander(get_rander, null):Rander;
	public var curBehavior(get_curbehavior,null):Behavior;
	public var curFrameIndex(get_curframeindex,null):Int;
	public var curFrame(get_curframe,null):Frame;
	public var spritesheet(get_spritesheet, null):Spritesheet;
	
	public var name(get_name, set_name):String;
	public var scaleX(get_scaleX,set_scaleX):Float;
	public var scaleY(get_scaleY,set_scaleY):Float;
	
	public var x(get_x,set_x):Float;
	public var y(get_y,set_y):Float;
	
	public var width(get_width,set_width):Float;
	public var height(get_height,set_height):Float;
	public var rotation(get_rotation,set_rotation):Float;
	public var angle(get_angle,null):Float;
	public var alpha(get_alpha, set_alpha):Float;
	public var visible(get_visible,set_visible):Bool;
	
	
	public var color(get_color, set_color):Int;
	public var sprite(get_sprite, null):Sprite;
	
	private var tx:Float;
	private var ty:Float;
	private var t_angle:Float;
	private var t_dis:Float;
	public function new(t_spritesheet:Spritesheet) 
	{
		_spritesheet = t_spritesheet;
		_scaleX = 1;
		_scaleY = 1;
		_x = 0;
		_y = 0;
		_rotation = 0;
		_angle = 0;
		_alpha = 1;
		_visible = true;
		_color = 16777215;
		_red = 1;
		_green = 1;
		_blue = 1;
		_name = "$ani#" + Std.string(globalId);
		globalId += 1;
		behaviorComplete = false;
		this.showBehavior(_spritesheet.behaviors.keys().next());
		frameinx = 0;
		untyped if (behavior!=null&&_spritesheet.frames.length > 0&&curBehavior.frames.length>0) {
			untyped _curframe = _spritesheet.frames[curBehavior.frames [0]];
		}
	}
	private function get_sprite():Sprite {
		return _sprite;
	}
	private function get_rander():Rander {
		return _rander;
	}
	private function set_rander(v:Rander):Void {
		_rander = v;
		if (_rander != null) {
			updateRanderMode(_rander.blitMode);
		}else{
			clearBitmap();
		}
	}
	
	private inline function clearBitmap():Void {
		if (_bitmap!=null) {
			if (_bitmap.parent != null)_bitmap.parent.removeChild(_bitmap);
			_bitmap.bitmapData = null;
			_bitmap = null;
		}
		if (_sprite != null) {
			if (_sprite.parent!=null)_sprite.parent.removeChild(_sprite);
			_sprite = null;
		}
	}
	private function updateRanderMode(isBlitMode:Bool):Void {
		if (isBlitMode) {
			clearBitmap();
		}else {
			if (_bitmap == null) {
				_bitmap = new Bitmap();
				_bitmap.smoothing = true;
			}
			if (_sprite == null) {
				_sprite = new Sprite();
			}
			_sprite.addChild(_bitmap);
			_sprite.scaleX = _scaleX;
			_sprite.scaleY = _scaleY;
			_sprite.alpha = _alpha;
			_sprite.rotation = _rotation;
			_sprite.visible = _visible;
			_sprite.x = _x;
			_sprite.y = _y;
			tx = (_curframe.offsetX - behavior.originX);
			ty = (_curframe.offsetY - behavior.originY);
			_bitmap.name = _name;
			_bitmap.x =tx;
			_bitmap.y =ty;
			if (_curframe != null) _bitmap.bitmapData = untyped Spritesheet.getBitmapData(_spritesheet, _curframe);
			untyped if (rander!=null && rander.layer!=null) rander.layer.addChild(_sprite);
		}
	}
	private function get_scaleX():Float 
	{
		return _scaleX;
	}
	
	private function set_scaleX(v:Float):Float 
	{
		_scaleX = v;
		if (_sprite!=null && _sprite.parent!=null)_sprite.scaleX = v;
		return v;
	}
	private function set_scaleY(v:Float) :Float 
	{
		_scaleY = v;
		if (_sprite!=null && _sprite.parent!=null)_sprite.scaleY = v;
		return v;
	}
	
	private function get_scaleY():Float 
	{
		return _scaleY;
	}
	
	private function set_visible(v:Bool):Bool 
	{
		_visible = v;
		if (_sprite!=null && _sprite.parent!=null)_sprite.visible = v;
		return v;
	}
	
	private function get_visible():Bool 
	{
		return _visible;
	}
	
	
	private function set_x(v:Float):Float 
	{
		_x = v;
		if (_sprite != null && _sprite.parent != null)_sprite.x = _x;
		return v;
	}
	
	private function get_x():Float 
	{
		return _x;
	}
	
	private function set_y(v:Float):Float 
	{
		_y = v;
		if (_sprite != null && _sprite.parent != null)_sprite.y = _y;
		return v;
	}
	
	private function get_y():Float 
	{
		return _y;
	}
	
	private function set_alpha(v:Float):Float 
	{
		_alpha = v;
		if (_sprite!=null && _sprite.parent!=null)_sprite.alpha = v;
		return v;
	}
	
	private function get_alpha():Float 
	{
		return _alpha;
	}
	
	private function set_width(v:Float):Float {
		if (v < 0) v = 0;
		if (v == 0) {
			scaleX = 0;
		}else {
			scaleX = v / this.curFrame.width;
		}
		return v;
	}
	private function set_height(v:Float):Float {
		if (v < 0) v = 0;
		if (v == 0) {
			scaleY = 0;
		}else {
			scaleY = v / this.curFrame.height;
		}
		return v;
	}
	
	private function get_width():Float {
		if (curFrame == null) return 0;
		return this.curFrame.width * scaleX;
	}
	private function get_height():Float {
		if (curFrame == null) return 0;
		return this.curFrame.height * scaleY;
	}
	private function get_name():String {
		return _name;
	}
	private function set_name(v:String):String
	{
		if (rander != null) //更新名字
		{
			 untyped rander.updateChildName(this, _name, v);
			 if (_sprite!=null && _sprite.parent!=null)_sprite.name = v;
		}
		_name = v;
		return v;
	}
	private function get_angle():Float {
		return _angle;
	}
	private function get_rotation():Float {
		return _rotation;
	}
	private function set_rotation(v:Float):Float {
		if (v % 360 == 0) v = 0;
		_rotation = v;
		_angle = _rotation * 0.017453292519943295;
		if (_sprite!=null && _sprite.parent!=null)_sprite.rotation = v;
		return v;
	}
	private function set_color(v:Int):Int {
		_red =Math.round((v >> 16 & 0xFF) / 255 );
		_blue=Math.round((v >> 8 & 0xFF) / 255 );
		_green = Math.round((v & 0xFF) / 255 );
		_color = v;
		return v;
	}
	private function get_color():Int {
		return _color;
	}
	
	private function get_curbehavior():Behavior {
		return behavior;
	}
	private function get_curframe():Frame {
		return _curframe;
	}
	private function get_curframeindex():Int {
		return frameinx;
	}
	private function get_spritesheet():Spritesheet
	{
		return _spritesheet;
	}

	public function addToContainer(_container:DisplayObjectContainer):DisplayObject{
		if (_rander != null) {
			_rander.removeChild(this);
			updateRanderMode(false);
		}else {
			if (_sprite == null)
			{
				updateRanderMode(false);
			}
		}
		previousTime=Lib.getTimer ();
		Lib.current.stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
		return _container.addChild(_sprite);
	}
	private function onEnterFrame(e:Event):Void {
		update(Lib.getTimer() - previousTime);
		previousTime = Lib.getTimer ();
		if (onUpdate != null) onUpdate();
		updateed();
	}
	public function removeFromContainer(_container:DisplayObjectContainer):Void {
		if (_rander != null) return ;
		Lib.current.stage.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
		if(_sprite!=null)_container.removeChild(_sprite);
	}
	public function showBehavior (name:String):Void {
		
		behavior = _spritesheet.behaviors.get (name);
		
		if (behavior != null) {
			timeElapsed = 0;
			behaviorComplete = false;
			
			loopTime = Std.int ((behavior.frames.length / behavior.frameRate) * 1000);
		} else {
			behaviorComplete = true;
			
		}
		
	}
	
	
	public function showBehaviors (names:Array <String>):Void {
		
		behaviorQueue = names;
		
		if (behaviorQueue != null && behaviorQueue.length > 0) {
			
			showBehavior (behaviorQueue.shift ());
			
		}
		
	}
	
	@:keep private function updateed():Void {
		if (behaviorComplete) {
			
			if (behaviorQueue != null && behaviorQueue.length > 0) {
				
				showBehavior (behaviorQueue.shift ());
			} 	
		}
	}

	@:keep private function update (deltaTime:Int):Void {
		
		if (!behaviorComplete) {
			
			timeElapsed += deltaTime;
			
			var ratio:Float = timeElapsed / loopTime;
			
			if (ratio >= 1) {
				
				if (behavior.loop) {
					
					ratio -= Math.floor (ratio);
					
				} else {
					
					behaviorComplete = true;
					ratio = 1;
					
				}
				
			}
			
			frameinx = Math.round (ratio * (behavior.frames.length - 1));
			untyped _curframe = _spritesheet.frames[behavior.frames [frameinx]];
			if (_bitmap != null && _sprite.parent!=null) {
				tx = (_curframe.offsetX - behavior.originX);
				ty = (_curframe.offsetY - behavior.originY);
				_bitmap.x =tx;
				_bitmap.y =ty;
				untyped _bitmap.bitmapData=Spritesheet.getBitmapData(_spritesheet, _curframe);
			}
		}
	}
}